package com.up.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.State;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;

public class ImageThreadLoader {
	
	private String diskurl;
	private CompressFormat compressedImageFormat = CompressFormat.PNG;
	private int cachedImageQuality = 75;
	private Context context;
	private final HashMap<String, SoftReference<Bitmap>> Cache = new HashMap<String,  SoftReference<Bitmap>>();
	
	private final class QueueItem {
		public URL url;
		public ImageLoadedListener listener;
	}
	private final ArrayList<QueueItem> Queue = new ArrayList<QueueItem>();

	private final Handler handler = new Handler();	// Assumes that this is started from the main (UI) thread
	private Thread thread;
	private QueueRunner runner = new QueueRunner();;	
	
	/** Creates a new instance of the ImageThreadLoader */
	public ImageThreadLoader(Context context) {
		this.context = context;
		this.diskurl = context.getApplicationContext().getCacheDir() + "/upcache/imagecache";
		new File(diskurl).mkdirs();
		thread = new Thread(runner);
	}
	
	private File getImageFile(String imageUrl) {
        String fileName = Integer.toHexString(imageUrl.hashCode()) + "."
                + compressedImageFormat.name();
        return new File(this.diskurl + "/" + fileName);
    } 
	private String getFullPath(String imageUrl){
		return this.diskurl + "/" + Integer.toHexString(imageUrl.hashCode()) + "."
        + compressedImageFormat.name();
	}
	
	public interface ImageLoadedListener {
		public void imageLoaded(Bitmap imageBitmap );
	}
	
	private class QueueRunner implements Runnable {
		public void run() {
			synchronized(this) {
				while(Queue.size() > 0) {
					final QueueItem item = Queue.remove(0);
					
					// If in the cache, return that copy and be done
					if( Cache.containsKey(item.url.toString()) && Cache.get(item.url.toString()) != null) {
						// Use a handler to get back onto the UI thread for the update
						
						handler.post(new Runnable() {
							public void run() {
								if( item.listener != null ) {
									// NB: There's a potential race condition here where the cache item could get
									//     garbage collected between when we post the runnable and it's executed.
									//     Ideally we would re-run the network load or something.
									SoftReference<Bitmap> ref = Cache.get(item.url.toString());
									if( ref != null ) {
										item.listener.imageLoaded(ref.get());
									}
								}
							}
						});
					} else {
						
						final Bitmap bmp = readBitmapFromNetwork(item.url);
						
						if( bmp != null ) {
							Cache.put(item.url.toString(), new SoftReference<Bitmap>(bmp));
							try{
								File imageFile = getImageFile(item.url.toString());
								imageFile.createNewFile();
								FileOutputStream ostream = new FileOutputStream(imageFile);
								bmp.compress(compressedImageFormat, cachedImageQuality, ostream);
				                ostream.close();
							}catch(Throwable e){
								
							}
							
							// Use a handler to get back onto the UI thread for the update
							handler.post(new Runnable() {
								public void run() {
									if( item.listener != null ) {
										item.listener.imageLoaded(bmp);
									}
								}
							});
							
						}
					}

				}
			}
		}
	}
	
	public Bitmap loadImage( final String uri, final ImageLoadedListener listener) throws MalformedURLException {
		// If it's in the cache, just get it and quit it
		Log.e("*********", "--1");
		if( Cache.containsKey(uri)) {
			
			SoftReference<Bitmap> ref = Cache.get(uri);
			if( ref != null ) {
				return ref.get();
			}
		}
		Log.e("*********", "--2");
		File imageFile = getImageFile(uri);
        if (imageFile.exists()) {
        	
        	String path = getFullPath(uri);
        	Drawable draw = Drawable.createFromPath(path);
        	Bitmap bit = ((BitmapDrawable)draw).getBitmap();
        	return bit;
        }
        Log.e("*********", "--3");
		QueueItem item = new QueueItem();
		item.url = new URL(uri);
		item.listener = listener;
		Queue.add(item);
		
		
		// start the thread if needed
		if( thread.getState() == State.NEW) {
			thread.start();
		} else if( thread.getState() == State.TERMINATED) {
			thread = new Thread(runner);
			thread.start();
		}
		
		return null;
	}	

	public static Bitmap readBitmapFromNetwork( URL url ) {
		InputStream is = null;
		BufferedInputStream bis = null;
		Bitmap bmp = null;
		Log.e("*********", "--4");
		try {
			URLConnection conn = url.openConnection();
			conn.connect();
			is = conn.getInputStream();
			bis = new BufferedInputStream(is);
			bmp = BitmapFactory.decodeStream(bis);
		} catch (MalformedURLException e) {
			Log.e("*************", "Bad ad URL", e);
		} catch (IOException e) {
			Log.e("******************", "Could not get remote ad image", e);
		} finally {
			try {
				if( is != null )
					is.close();
				if( bis != null )
					bis.close();
			} catch (IOException e) {
				Log.w("*************", "Error closing stream.");
			}
		}
		Log.e("*********", "--5");
		return bmp;
	}	
}
